package com.wei.type2;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 简单的自定义线程池，新增拒绝策略以及关闭方法
 *
 * @author :sunwei
 * @description:
 * @date create in 23:00  2021/7/28
 */
public class SimpleThreadPool {
    
    //任务队列
    private static final LinkedList<Runnable> TASK_QUEUE = new LinkedList<>();
    
    //执行队列
    private static List<WorkerTask> THREAD_QUEUE;
    
    //线程池大小
    private int size;
    
    //队列大小
    private int queueSize;
    
    //拒绝策略
    private DiscardPolicy discardPolicy;
    
    public final static DiscardPolicy DEFAULT_DISCARD_POLICY=()->{throw new DiscardRuntimeException("task queue is full ...");};
    
    //默认线程池大小
    private static final int DEFAULT_SIZE = 6;
    
    //默认队列大小
    private static final int DEFAULT_QUEUE_SIZE = 10;
    
    //线程池状态
    private boolean destory = false;
    
    public SimpleThreadPool() {
        this(DEFAULT_SIZE, DEFAULT_QUEUE_SIZE, DEFAULT_DISCARD_POLICY);
    }
    
    public SimpleThreadPool(int size, int queueSize, DiscardPolicy discardPolicy) {
        this.size = size;
        this.queueSize = queueSize;
        this.discardPolicy = discardPolicy;
        init();
    }
    
    private synchronized void init() {
        THREAD_QUEUE = new ArrayList();
        for (int i = 0; i < size; i++) {
            WorkerTask task = new WorkerTask(Thread.currentThread().getThreadGroup(), "MyThreadPool-" + i);
            task.start();
            THREAD_QUEUE.add(task);
        }
    }
    
    public void submit(Runnable target) {
        if (destory) {
            throw new IllegalStateException("pool has been destroy,can't submit task.");
        }
        synchronized (TASK_QUEUE) {
            if (TASK_QUEUE.size() > queueSize) {
                //当队列满时,有提交则执行拒绝策略
                discardPolicy.discard();
            }
            TASK_QUEUE.addLast(target);
            System.out.println("TASK_QUEUE.size() is : "+TASK_QUEUE.size());
            TASK_QUEUE.notifyAll();
        }
    }
    
    public void shutdown() throws InterruptedException {
        destory = true;
        while(!TASK_QUEUE.isEmpty()){
            Thread.sleep(50);
            int initVal = THREAD_QUEUE.size();
            while(initVal>0) {
                for (WorkerTask task : THREAD_QUEUE) {
                    if(task.getTaskState()==TaskState.BLOCKED){
                        //中断任务
                        task.interrupt();
                        task.close();
                    }else{
                        //等待完成
                        Thread.sleep(10);
                        task.interrupt();
                    }
                    initVal--;
                }
            }
            System.out.println(TASK_QUEUE.size());
        }
    
        for (WorkerTask task : THREAD_QUEUE) {
            task.interrupt();
            task.close();
        }
    }
    
    enum TaskState {
        FREE, RUNNABLE, BLOCKED, RUNNING, DEAD
    }
    
    //工作任务
    private static class WorkerTask extends Thread {
        
        //任务状态
        private volatile TaskState taskState;
        
        public TaskState getTaskState() {
            return taskState;
        }
        
        @Override
        public void run() {
            OUTER:
            while (taskState != TaskState.DEAD) {
                Runnable runnable;
                synchronized (TASK_QUEUE) {
                    while (TASK_QUEUE.isEmpty()) {
                        taskState = TaskState.BLOCKED;
                        try {
                            TASK_QUEUE.wait();
                        } catch (InterruptedException e) {
                            System.out.println(Thread.currentThread().getName() + " has been interrupted ");
                            taskState = TaskState.RUNNABLE;
                            break OUTER;
                        }
                    }
                    System.out.println("wait done!");
                    runnable = TASK_QUEUE.removeFirst();
                }
                if (runnable != null) {
                    taskState = TaskState.RUNNING;
                    runnable.run();
                    taskState = TaskState.FREE;
                }
            }
        }
        
        public void close() {
            taskState = TaskState.DEAD;
        }
        
        public WorkerTask(ThreadGroup group, String name) {
            super(group, name);
        }
        
    }
    
    public int getSize() {
        return size;
    }
    
    public int getQueueSize() {
        return queueSize;
    }
}
